package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.trade.OrderBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课表 服务实现类
 * </p>
 *
 * @author snow
 * @since 2023-10-20
 */
@Service
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    final CourseClient courseClient;
    final CatalogueClient catalogueClient;
    final LearningLessonMapper learningLessonMapper;
    final LearningRecordMapper learningRecordMapper;
    /**
     * 批量插入课程
     *
     * @param userId
     * @param courseIds
     */
    @Override
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //通过Feign远程调用课程服务拿到课程信息
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courseIds);

        //封装PO实体类填充过期时间
        List<LearningLesson> list = new ArrayList<>();
        for (CourseSimpleInfoDTO cinfo :
                cinfos) {
            LearningLesson learningLesson = new LearningLesson();
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(cinfo.getId());
            Integer validDuration = cinfo.getValidDuration();//课程有效期
            if (validDuration != null){
                learningLesson.setCreateTime(LocalDateTime.now());
                learningLesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
            }
            list.add(learningLesson);
        }

        //批量保存
        this.saveBatch(list);
    }

    /**
     * 分页查询我的课程
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryLessons(PageQuery query) {
        //获取当前登录用户
        Long userId = UserContext.getUser();
        //分页查询我的课表
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }

        //远程调用课程服务,给vo中的课程名,封面,章节数 赋值
        List<Long> courseId = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courseId);
        if (CollUtils.isEmpty(cinfos)){
            throw new BizIllegalException("课程不存在");
        }
        Map<Long, CourseSimpleInfoDTO> infoDTOMap = cinfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //将数据封装到vo中
        List<LearningLessonVO> learningLessonVOList = new ArrayList<>();
        records.forEach( record ->{
            LearningLessonVO vo =  BeanUtils.copyBean(record,LearningLessonVO.class);
            CourseSimpleInfoDTO infoDTO = infoDTOMap.get(record.getCourseId());
            if (infoDTO != null){
                vo.setCourseName(infoDTO.getName());
                vo.setCourseCoverUrl(infoDTO.getCoverUrl());
                vo.setSections(infoDTO.getSectionNum());
            }
            learningLessonVOList.add(vo);
        });


        //返回
        return PageDTO.of(page,learningLessonVOList);
    }

    /**
     * 查询正在学习的课程
     *
     * @return
     */
    @Override
    public LearningLessonVO queryMyCurrentLessons() {
        //获取当前登录用户的id

        Long userId = UserContext.getUser();

        //查询当前用户最近学习课程 按最近学习时间做降序排序 取第一条 正在学习中的 status = 1
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId,userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (learningLesson == null){
            return null;
        }
        //远程调用课程服务给vo中的课程名 封面 章节数 赋值
        CourseFullInfoDTO cinfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
        if (cinfo == null){
            throw new BizIllegalException("课程不存在");
        }
        //查询当前用户课表中 总的课程数
        Integer count = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        //远程调用课程服务获取小节名称,和小节编号
        Long latestSectionId = learningLesson.getLatestSectionId();

        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(latestSectionId));
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)){
            throw new BizIllegalException("小节不存在");
        }

        //将po的数据封装到vo中返回
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(learningLesson,LearningLessonVO.class);
        learningLessonVO.setCourseName(cinfo.getName());
        learningLessonVO.setCourseCoverUrl(cinfo.getCoverUrl());
        learningLessonVO.setSections(cinfo.getSectionNum());
        learningLessonVO.setCourseAmount(count);

        CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
        learningLessonVO.setLatestSectionName(cataSimpleInfoDTO.getName());
        learningLessonVO.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex());



        return learningLessonVO;
    }

    /**
     * 检查课程是否有效
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        //获取当前登录用户id
        Long userId = UserContext.getUser();
        //获取课程信息 CourseId UserId
        LearningLesson lesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        //判断课程是否为空
        if (BeanUtils.isEmpty(lesson)){
            return null;
        }
        //判断课程是否过期
        LocalDateTime expireTime = lesson.getExpireTime();
        if (expireTime != null && expireTime.isBefore(LocalDateTime.now())){
            return null;
        }
        //返回课程id
        return lesson.getId();
    }

    /**
     * 查询用户课表中指定课程状态
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryLessonStatus(Long courseId) {
        //获取到当前登录用户id
        Long userId = UserContext.getUser();
        //根据课程id查询课程信息
        LearningLesson lesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        //判断是否为空
        if (lesson == null){
            return null;
        }
        //封装为LearningLessonVO返回
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);


        return learningLessonVO;
    }

    /**
     * 通过订单信息删除用户课程
     *
     * @param orderBasicDTO
     */
    @Override
    public void deleteCourse(OrderBasicDTO orderBasicDTO) {

        //通过用户id 和 课程 id 删除课程
        Wrapper<LearningLesson> wrapper = new LambdaQueryWrapper<LearningLesson>()
                .eq(LearningLesson::getUserId,orderBasicDTO.getUserId())
                .in(LearningLesson::getUserId,orderBasicDTO.getCourseIds());

        learningLessonMapper.delete(wrapper);

    }

    /**
     * 统计课程的学习人数
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer queryCountLearningLessonByCourse(Long courseId) {
        Wrapper<LearningLesson> wrapper = new LambdaQueryWrapper<LearningLesson>()
                .eq(LearningLesson::getCourseId,courseId);
        return this.count(wrapper);
    }

    /**
     * 创建学习计划
     *
     * @param learningPlanDTO
     */
    @Override
    public void createLearningPlans(LearningPlanDTO learningPlanDTO) {
        //获取当前登录用户id
        Long userId = UserContext.getUser();
        //查询课表
        LearningLesson learningLesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, learningPlanDTO.getCourseId())
                .one();
        if (learningLesson == null){
            throw new BizIllegalException("该课程没有加入课表");
        }
        //修改课表
//        learningLesson.setWeekFreq(learningPlanDTO.getFreq());
//        learningLesson.setPlanStatus(PlanStatus.PLAN_RUNNING);
//        this.updateById(learningLesson);
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq,learningPlanDTO.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getId,learningLesson.getId())
                .update();

    }

    @Override
    public LearningPlanPageVO queryMyPlans(PageQuery query) {
        //获取当前登录用户id
        Long userId = UserContext.getUser();
        //Todo 查询积分

        //查询本周学习计划总数据
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("sum(week_freq) as plans_total");
        queryWrapper.eq("user_id",userId);
        queryWrapper.in("status",LessonStatus.NOT_BEGIN,LessonStatus.LEARNING);
        queryWrapper.eq("plan_status",PlanStatus.PLAN_RUNNING);
        Map map = this.getMap(queryWrapper);
        Integer plansTotal = 0;
        if (map != null && map.get("plans_total") != null) {
            plansTotal = Integer.valueOf(map.get("plans_total").toString());
        }
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        //查询本周已学习的计划总数据
        Integer weekFinishPlanNum = learningRecordMapper.selectCount(Wrappers.<LearningRecord>lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .between(LearningRecord::getFinishTime, weekBeginTime, weekEndTime));
        //查询课表数据 条件 userid status in(0,1) plan_status 分页
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId,userId)
                .in(LearningLesson::getStatus,LessonStatus.NOT_BEGIN,LessonStatus.LEARNING)
                .eq(LearningLesson::getPlanStatus,PlanStatus.PLAN_RUNNING)
                .page(query.toMpPage("latest_learn_time",false));

        List<LearningLesson> records = page.getRecords();
        //如果记录为空则返回
        if (CollUtils.isEmpty(records)){
            LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
            learningPlanPageVO.setTotal(0L);
            learningPlanPageVO.setPages(0L);
            learningPlanPageVO.setList(CollUtils.emptyList());
            return learningPlanPageVO;
        }

        //远程调用课程服务 获取课程信息
        Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(cinfos)){
            throw new BizIllegalException("课程不存在");
        }
        //将cinfo的 list结构 转为 map 结构
        Map<Long, CourseSimpleInfoDTO> cInfosMap = cinfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //查询学习记录表 本周 当前用户下 每一门课下学习的小节数量
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.select("lesson_id as lessonId","count(*) as user_id");
        wrapper.eq("user_id",userId);
        wrapper.eq("finished",true);
        wrapper.between("finish_time",weekBeginTime,weekEndTime);
        wrapper.groupBy("lesson_id");

        List<LearningRecord> learningRecords = learningRecordMapper.selectList(wrapper);
        //Map中的key是lessonId value是当前用户对该课程下已学习的小节数量
            Map<Long, Long> courseWeekFinishNum = learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId, c -> c.getUserId()));
        //封装VO返回
        LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
        learningPlanPageVO.setWeekTotalPlan(plansTotal);
        learningPlanPageVO.setWeekFinished(weekFinishPlanNum);

        List<LearningPlanVO> voList = new ArrayList<>();
        for (LearningLesson record:records){
            LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            CourseSimpleInfoDTO infoDTO = cInfosMap.get(record.getCourseId());
            if (infoDTO != null){

                learningPlanVO.setCourseName(infoDTO.getName());//课程名
                learningPlanVO.setSections(infoDTO.getSectionNum());//课程下的总小节数
            }


            learningPlanVO.setWeekLearnedSections(courseWeekFinishNum.getOrDefault(record.getId(),0L).intValue());

            voList.add(learningPlanVO);
        }
        learningPlanPageVO.setList(voList);

        return learningPlanPageVO;
    }
}
